
#include <BNode>
#include <BShape>
#include <BRender>
#include <BMouseEvent>
#include <BViewer>
#include <BPickHit>
#include <BGeometry>
#include <BMesh>
#include <BFont>
#include <BPainter>
#include <BImage>
#include <BCamera>
#include <BKeyEvent>
#include <BSystem>
#include <BCursor>
#include <BStyle>

#include "operas/TransOpera.h"
#include "PrimitiveHandler.h"

PrimitiveHandler::PrimitiveHandler()
{
	_showNormals = false;
	_normalLengthRatio = 0.006f;
	_slideTimes = 0;

	_gridLinesVisible = true;
	_dirtyGridLines = true;
	_gridSize.set(100, 100);
	_gridSegment = 20;
	_gridColor.set(128, 128, 128);

	_visibleBaseAxes = HA_XY;
	_baseAxisXColor.set(200, 0, 0);
	_baseAxisYColor.set(0, 200, 0);
	_baseAxisZColor.set(0, 0, 200);

	_target = 0;
	_leftPressed = false;
	_ctrlDown = false;
	_handleMode = HM_None;
	_handleAxis = HA_None;

	_cone_x = new BCone();
	_cone_x->setDepthTest(false);
	_cone_y = new BCone();
	_cone_y->setDepthTest(false);
	_cone_z = new BCone();
	_cone_z->setDepthTest(false);

	connect("target-changed", &PrimitiveHandler::slotTargetChanged);
}
PrimitiveHandler::~PrimitiveHandler()
{

}

void PrimitiveHandler::setGridLineVisible(bool gridLineVisible)
{
	if (_gridLinesVisible != gridLineVisible)
	{
		_gridLinesVisible = gridLineVisible;
		_dirtyGridLines = true;
		this->fresh();
	}
}
bool PrimitiveHandler::gridLineVisible() const
{
	return _gridLinesVisible;
}

void PrimitiveHandler::setGridSize(const BRealSize& gridSize)
{
	if (_gridSize != gridSize)
	{
		_gridSize = gridSize;
		_dirtyGridLines = true;
		this->fresh();
	}
}
const BRealSize& PrimitiveHandler::gridSize() const
{
	return _gridSize;
}

void PrimitiveHandler::setGridSegment(int gridSegment)
{
	if (_gridSegment != gridSegment)
	{
		_gridSegment = gridSegment;
		_dirtyGridLines = true;
		this->fresh();
	}
}
int PrimitiveHandler::gridSegment() const
{
	return _gridSegment;
}

void PrimitiveHandler::setGridColor(const BColor& color)
{
	if (_gridColor != color)
	{
		_gridColor = color;
		this->fresh();
	}
}
const BColor& PrimitiveHandler::gridColor() const
{
	return _gridColor;
}

void PrimitiveHandler::setShowNormals(bool showNormals)
{
	if (_showNormals != showNormals)
	{
		_showNormals = showNormals;
		this->fresh();
	}
}
bool PrimitiveHandler::showNormals() const
{
	return _showNormals;
}

void PrimitiveHandler::setNormalsFlags(const BString& normalsFlag)
{
	if (_normalsFlag != normalsFlag)
	{
		_normalsFlag = normalsFlag;
	}
}
const BString& PrimitiveHandler::normalsFlag() const
{
	return _normalsFlag;
}

void PrimitiveHandler::setNormalLengthRatio(float normalLengthRatio)
{
	if (_normalLengthRatio != normalLengthRatio)
	{
		_normalLengthRatio = normalLengthRatio;
		this->fresh();
	}
}
float PrimitiveHandler::normalLengthRatio() const
{
	return _normalLengthRatio;
}

void PrimitiveHandler::setHandleMode(HandleMode hmode)
{
	if (_handleMode != hmode)
	{
		_handleMode = hmode;
		_dirtyAxis = true;
		this->fresh();
	}
}
HandleMode PrimitiveHandler::handleMode() const
{
	return _handleMode;
}

void PrimitiveHandler::setHandleAxis(HandleAxis haxis)
{
	if (_handleAxis != haxis)
	{
		_handleAxis = haxis;
		_dirtyAxis = true;
		this->fresh();
	}
}
HandleAxis PrimitiveHandler::handleAxis() const
{
	return _handleAxis;
}

void PrimitiveHandler::setVisibleBaseAxes(int visibleAxes)
{
	_visibleBaseAxes = visibleAxes;
	this->fresh();
}
int PrimitiveHandler::visibleAxes() const
{
	return _visibleBaseAxes;
}

void PrimitiveHandler::setBaseAxisXColor(const BColor& baseAxisXColor)
{
	_baseAxisXColor = baseAxisXColor;
	this->fresh();
}
const BColor& PrimitiveHandler::baseAxisXColor() const
{
	return _baseAxisXColor;
}

void PrimitiveHandler::setBaseAxisYColor(const BColor& baseAxisYColor)
{
	_baseAxisYColor = baseAxisYColor;
	this->fresh();
}
const BColor& PrimitiveHandler::baseAxisYColor() const
{
	return _baseAxisYColor;
}

void PrimitiveHandler::setBaseAxisZColor(const BColor& baseAxisZColor)
{
	_baseAxisZColor = baseAxisZColor;
	this->fresh();
}
const BColor& PrimitiveHandler::baseAxisZColor() const
{
	return _baseAxisZColor;
}

void PrimitiveHandler::focus(const BSpace& space)
{
	BVector center = space.center();
	BVector direct(0, 1, 1);
	if (this->camera()->position() != center)
		direct = this->camera()->position() - center;
	direct.normalize();
	_slidePosition = center + direct * space.radius() * 3;
	_slideCenter = center;
	_slideUp.set(0, 0, 1);
	_slideTimes = 20;
}
void PrimitiveHandler::focus(const BBox& box)
{
	BVector center = box.center();
	BVector direct(0, 1, 1);
	if (this->camera()->position() != center)
		direct = this->camera()->position() - center;
	direct.normalize();
	_slidePosition = center + direct * box.radius() * 3;
	_slideCenter = center;
	_slideUp.set(0, 0, 1);
	_slideTimes = 20;
}

BLineArray* PrimitiveHandler::createFaceNormalLines(BGeometry* geometry)
{
	BLineArray* normalLines = geometry->property("face-normals");
	if (!normalLines)
	{
		normalLines = new BLineArray();
		geometry->setProperty("face-normals", normalLines);
		BReal nlen = geometry->space().radius() * _normalLengthRatio * 0.1f;
		BVectorArray* vertices = geometry->vertices();
		BVectorArray* normals = geometry->normals();
		for (int e = 0; e < geometry->elementCount(); e++)
		{
			BElement* element = geometry->element(e);
			if (element->primitive() == Primitive_Triangles)
			{
				if (const BIntArray* indices = element->indices())
				{
					for (int i = 0; i < indices->size(); i += 3)
					{
						int ia = indices->at(i);
						int ib = indices->at(i + 1);
						int ic = indices->at(i + 2);
						const BVector& va = vertices->at(ia);
						const BVector& vb = vertices->at(ib);
						const BVector& vc = vertices->at(ic);
						const BVector& na = normals->at(ia);
						const BVector& nb = normals->at(ib);
						const BVector& nc = normals->at(ic);
						BVector v = (va + vb + vc) / 3;
						BVector n = (na + nb + nc) / 3;
						normalLines->append().set(v, v + n);
					}
					continue;
				}
				if (const BPieceArray* pieces = element->pieces())
				{
					for (int i = 0; i < pieces->size(); i += 3)
					{
						const BPiece& pa = pieces->at(i);
						const BPiece& pb = pieces->at(i + 1);
						const BPiece& pc = pieces->at(i + 2);
						const BVector& va = vertices->at(pa.v());
						const BVector& vb = vertices->at(pb.v());
						const BVector& vc = vertices->at(pc.v());
						const BVector& na = normals->at(pa.vn());
						const BVector& nb = normals->at(pb.vn());
						const BVector& nc = normals->at(pc.vn());
						BVector v = (va + vb + vc) / 3;
						BVector n = (na + nb + nc) / 3;
						normalLines->append().set(v, v + n);
					}
					continue;
				}
				for (int i = 0; i < element->count(); i += 3)
				{
					int ia = element->first() + i;
					int ib = element->first() + i + 1;
					int ic = element->first() + i + 2;
					const BVector& va = vertices->at(ia);
					const BVector& vb = vertices->at(ib);
					const BVector& vc = vertices->at(ic);
					const BVector& na = normals->at(ia);
					const BVector& nb = normals->at(ib);
					const BVector& nc = normals->at(ic);
					BVector v = (va + vb + vc) / 3;
					BVector n = (na + nb + nc) / 3;
					normalLines->append().set(v, v + n);
				}
			}
		}
	}
	return normalLines;
}
BLineArray* PrimitiveHandler::createFaceNormalLines(BMesh* mesh)
{
	BLineArray* normalLines = mesh->property("face-normals");
	if (!normalLines)
	{
		normalLines = new BLineArray();
		mesh->setProperty("face-normals", normalLines);
		BVectorArray* vertices = mesh->vertices();
		BVectorArray* normals = mesh->normals();
		if (BFaceArray* faces = mesh->faces())
		{
			for (int f = 0; f < faces->size(); f++)
			{
				BFace& face = faces->at(f);
				const BVector& va = vertices->at(face.a());
				const BVector& vb = vertices->at(face.b());
				const BVector& vc = vertices->at(face.c());
				const BVector& na = normals->at(face.a());
				const BVector& nb = normals->at(face.b());
				const BVector& nc = normals->at(face.c());
				BVector v = (va + vb + vc) / 3;
				BVector n = (na + nb + nc) / 3;
				normalLines->append().set(v, v + n);
			}
		}
		else
		{
			for (int i = 0; i < vertices->size(); i += 3)
			{
				const BVector& va = vertices->at(i);
				const BVector& vb = vertices->at(i + 1);
				const BVector& vc = vertices->at(i + 2);
				const BVector& na = normals->at(i);
				const BVector& nb = normals->at(i + 1);
				const BVector& nc = normals->at(i + 2);
				BVector v = (va + vb + vc) / 3;
				BVector n = (na + nb + nc) / 3;
				normalLines->append().set(v, v + n);
			}
		}
	}
	return normalLines;
}
void PrimitiveHandler::drawNormals(BShape* shape, BRender& render)
{
	if (_showNormals == false)
		return;
	render.setLighting(false);
	render.setColor(255, 0, 0);
	if (BGeometry* geometry = dynamic_cast<BGeometry*>(shape))
	{
		BReal nlen = geometry->space().radius() * _normalLengthRatio * 0.1f;
		if (_normalsFlag == "Point-Normals")
		{
			BVectorArray* vertices = geometry->vertices();
			BVectorArray* normals = geometry->normals();
			for (int vi = 0; vi < vertices->size(); vi++)
			{
				const BVector& v = vertices->at(vi);
				const BVector& n = normals->at(vi);
				render.drawLine(v, v + n * nlen);
			}
		}
		else
		{
			BLineArray* normalLines = createFaceNormalLines(geometry);
			for (int i = 0; i < normalLines->size(); i++)
			{
				const BLine& line = normalLines->at(i);
				render.drawLine(line.begin(), line.begin() + line.direct() * nlen);
			}
		}
		return;
	}
	if (BMesh* mesh = dynamic_cast<BMesh*>(shape))
	{
		BReal nlen = mesh->space().radius() * _normalLengthRatio * 0.1f;
		if (_normalsFlag == "Point-Normals")
		{
			BVectorArray* vertices = mesh->vertices();
			BVectorArray* normals = mesh->normals();
			for (int vi = 0; vi < vertices->size(); vi++)
			{
				const BVector& v = vertices->at(vi);
				const BVector& n = normals->at(vi);
				render.drawLine(v, v + n * nlen);
			}
		}
		else
		{
			BLineArray* normalLines = createFaceNormalLines(mesh);
			for (int i = 0; i < normalLines->size(); i++)
			{
				const BLine& line = normalLines->at(i);
				render.drawLine(line.begin(), line.begin() + line.direct() * nlen);
			}
		}
		return;
	}
}
void PrimitiveHandler::freshFrustum()
{
	BCamera* camera = this->camera();
	BReal near = camera->near();
	BReal far = camera->far();

	_frustum.near_v0 = this->viewer()->vertex(_selectRect.leftTop(), near);
	_frustum.near_v1 = this->viewer()->vertex(_selectRect.leftBottom(), near);
	_frustum.near_v2 = this->viewer()->vertex(_selectRect.rightBottom(), near);
	_frustum.near_v3 = this->viewer()->vertex(_selectRect.rightTop(), near);

	_frustum.far_v0 = this->viewer()->vertex(_selectRect.leftTop(), far);
	_frustum.far_v1 = this->viewer()->vertex(_selectRect.leftBottom(), far);
	_frustum.far_v2 = this->viewer()->vertex(_selectRect.rightBottom(), far);
	_frustum.far_v3 = this->viewer()->vertex(_selectRect.rightTop(), far);

	_frustum.freshPlanes();

}
void PrimitiveHandler::frustumPick()
{
	BArray<BPickHitHolder> pickHits;
	BScene* scene = this->scene();
	for (int i = 0; i < scene->shapeCount(); i++)
	{
		BShape* shape = scene->shape(i);
		if (_frustum.clip(shape->space()))
			continue;
		BPickHit* hit = new BPickHit();
		hit->setShape(shape);
		pickHits.append(hit);
	}
	for (int i = 0; i < scene->nodeCount(); i++)
	{
		BNode* node = scene->node(i);
		if (_frustum.clip(node->space()))
			continue;
		BMatrix inverMatrix = node->matrix().inverse();
		Frustum localFrustum = _frustum * inverMatrix;
		for (int s = 0; s < node->shapeCount(); s++)
		{
			BShape* shape = node->shape(s);
			if (localFrustum.clip(shape->space()))
				continue;
			BPickHit* hit = new BPickHit();
			hit->setNode(node);
			hit->setShape(shape);
			pickHits.append(hit);
		}
	}
}

void PrimitiveHandler::startTransform(const BMatrix& matrix)
{
	if (_target.empty())
		return;
	if (_target->pickHitCount() == 1)
	{
		BPickHit* hit = _target->pickHit(0);
		if (BShape* shape = hit->shape())
		{
			_transOpera = new ShapeTransOpera(shape, hit->node());
		}
		else if (BNode* node = hit->node())
		{
			_transOpera = new NodeTransOpera(node);
		}
		else if (BGroup* group = hit->group())
		{
			_transOpera = new GroupTransOpera(group);
		}
	}
	else
	{
		MultiTransOpera* transOpera = new MultiTransOpera();
		for (int i = 0; i < _target->pickHitCount(); i++)
		{
			BPickHit* hit = _target->pickHit(0);
			if (BShape* shape = hit->shape())
			{
				transOpera->insertShape(shape, hit->node());
			}
			else if (BNode* node = hit->node())
			{
				transOpera->addNode(node);
			}
			else if (BGroup* group = hit->group())
			{
				transOpera->addGroup(group);
			}
		}
		_transOpera = transOpera;
	}
	_transOpera->setOrigin(matrix);
	_transOpera->setMatrix(matrix);
}
void PrimitiveHandler::transforming(const BMatrix& matrix)
{
	if (_target && _transOpera)
	{
		_transOpera->setMatrix(matrix);
		_transOpera->redo();
		this->fresh();
	}
}
void PrimitiveHandler::finishTransform(const BMatrix& matrix)
{
	if (_target && _transOpera)
	{
		_transOpera->setMatrix(matrix);
		emit("opera", _transOpera);
		_target->dirty();
		_transOpera = 0;
		this->fresh();
	}
}

void PrimitiveHandler::freshTargetMatrix()
{
	BMatrix basicMatrix;
	BMatrix matrix;
	if (_target)
	{
		if (BShape* shape = _target->shape())
		{
			matrix = shape->matrix();
			if (BNode* node = _target->node())
				basicMatrix = node->matrix();
		}
		else if (BNode* node = _target->node())
		{
			matrix = node->matrix();
		}
		else
		{
			matrix = _target->space().center();
		}
	}
	_basicMatrix = basicMatrix;
	_origin = matrix;
	_matrix = matrix;
	_dirtyAxis = true;
	transforming(_matrix);
	this->fresh();
}
void PrimitiveHandler::freshAxis()
{
	if (_target.empty())
		return;
	freshMoveAxis();
	freshRotateAxis();
	freshScaleAxis();
}
void PrimitiveHandler::freshMoveAxis()
{
	BVector center = _matrix.position();

	_axis_x.set(center, center + BVector(_axisSize, 0, 0));
	_axis_y.set(center, center + BVector(0, _axisSize, 0));
	_axis_z.set(center, center + BVector(0, 0, _axisSize));

	BReal coneSize = _axisSize * (BReal)0.1;
	_cone_x->setRadius(coneSize / 2);
	_cone_x->setHeight(coneSize);
	_cone_x->setPosition(_axis_x.end());
	_cone_x->setRotate(BQuater(BVector(0, 0, 1), BVector(1, 0, 0)));

	_cone_y->setRadius(coneSize / 2);
	_cone_y->setHeight(coneSize);
	_cone_y->setPosition(_axis_y.end());
	_cone_y->setRotate(BQuater(BVector(0, 0, 1), BVector(0, 1, 0)));

	_cone_z->setRadius(coneSize / 2);
	_cone_z->setHeight(coneSize);
	_cone_z->setPosition(_axis_z.end());

	BReal quadSize = _axisSize / (BReal)3.0;
	_quad_xy.a() = center;
	_quad_xy.b() = center + BVector(quadSize, 0, 0);
	_quad_xy.c() = center + BVector(quadSize, quadSize, 0);
	_quad_xy.d() = center + BVector(0, quadSize, 0);

	_quad_yz.a() = center;
	_quad_yz.b() = center + BVector(0, quadSize, 0);
	_quad_yz.c() = center + BVector(0, quadSize, quadSize);
	_quad_yz.d() = center + BVector(0, 0, quadSize);

	_quad_xz.a() = center;
	_quad_xz.b() = center + BVector(quadSize, 0, 0);
	_quad_xz.c() = center + BVector(quadSize, 0, quadSize);
	_quad_xz.d() = center + BVector(0, 0, quadSize);

}
void PrimitiveHandler::freshRotateAxis()
{
	_rotateCircleXY.resize(24);
	_rotateCircleYZ.resize(24);
	_rotateCircleXZ.resize(24);
	if (_rotateSphere.empty())
		_rotateSphere = new BSphere();

	BReal unit = 2 * PIf / 24;

	for (int i = 0; i < 24; i++)
	{
		BReal x = cos(i * unit) * _axisSize;
		BReal y = sin(i * unit) * _axisSize;
		_rotateCircleXY[i] = BVector(x, y, 0);
	}

	for (int i = 0; i < 24; i++)
	{
		BReal y = cos(i * unit) * _axisSize;
		BReal z = sin(i * unit) * _axisSize;
		_rotateCircleYZ[i] = BVector(0, y, z);
	}

	for (int i = 0; i < 24; i++)
	{
		BReal x = cos(i * unit) * _axisSize;
		BReal z = sin(i * unit) * _axisSize;
		_rotateCircleXZ[i] = BVector(x, 0, z);
	}

	_rotateSphere->setRadius(_axisSize * (BReal)0.96);
}
void PrimitiveHandler::freshScaleAxis()
{

}

bool PrimitiveHandler::pickAxis(const BLine& line)
{
	BScene* scene = this->viewer()->scene();
	if (_target)
	{
		switch (_handleMode)
		{
		case HM_Move:
			return pickMoveAxis(line);
		case HM_Rotate:
			return pickRotateAxis(line);
		case HM_Scale:
			return pickScaleAxis(line);
		default:
			return false;
		}
	}
	return false;
}
bool PrimitiveHandler::pickMoveAxis(const BLine& line)
{
	BVector pos = _target->space().center();

	HandleAxis axis = HA_None;
	float ratio = 1;
	float ratio_xy = 0;
	if (line.intersect(_quad_xy, ratio_xy) && ratio_xy < ratio)
	{
		axis = HA_XY;
		ratio = ratio_xy;
	}
	float ratio_yz = 0;
	if (line.intersect(_quad_yz, ratio_yz) && ratio_yz < ratio)
	{
		axis = HA_YZ;
		ratio = ratio_yz;
	}
	float ratio_xz = 0;
	if (line.intersect(_quad_xz, ratio_xz) && ratio_xz < ratio)
	{
		axis = HA_XZ;
	}
	if (axis)
	{
		_handleAxis = axis;
		this->viewer()->fresh();
	}
	else
	{
		BReal disX = line.distance(_axis_x);
		BReal disY = line.distance(_axis_y);
		BReal disZ = line.distance(_axis_z);
		BReal pickRange = _axisSize / 20;
		if (disX < pickRange)
			axis = HA_X;
		if (disY < pickRange)
			axis = HA_Y;
		if (disZ < pickRange)
			axis = HA_Z;
		_handleAxis = axis;
		this->viewer()->fresh();
	}
	return _handleAxis != HA_None;
}
bool PrimitiveHandler::pickRotateAxis(const BLine& line)
{
	HandleAxis axis = HA_None;

	BQuater quat = _matrix.rotate();
	BVector center = _matrix.position();

	BVector foot = line.foot(center);
	BReal dist = (foot - center).length();
	if (dist < _axisSize)
	{
		BReal len = sqrt(_axisSize * _axisSize - dist * dist);
		BVector point = foot - line.direct() * len;

		BReal range = this->viewer()->unit(center) * 10;
		BVector axis_z = quat * BVector(0, 0, 1);
		BVector axis_y = quat * BVector(0, 1, 0);
		BVector axis_x = quat * BVector(1, 0, 0);

		BPlane plane_xy(axis_z, center);
		BReal dist_xy = abs(plane_xy.distance(point));

		BPlane plane_yz(axis_x, center);
		BReal dist_yz = abs(plane_yz.distance(point));

		BPlane plane_xz(axis_y, center);
		BReal dist_xz = abs(plane_xz.distance(point));

		if (dist_xy < range && dist_xy < dist_yz && dist_xy < dist_xz)
			axis = HA_XY;
		else if (dist_yz < range && dist_yz < dist_xy && dist_yz < dist_xz)
			axis = HA_YZ;
		else if (dist_xz < range && dist_xz < dist_xy && dist_xz < dist_yz)
			axis = HA_XZ;
	}
	if (_handleAxis != axis)
	{
		_handleAxis = axis;
		this->viewer()->fresh();
	}
	return _handleAxis;
}
bool PrimitiveHandler::pickScaleAxis(const BLine& line)
{
	return false;
}

void PrimitiveHandler::applyOpera(const BLine& line)
{
	if (!_target || !_transOpera)
		return;
	if (_handleMode == HM_Move)
		applyMoveOpera(line);
	if (_handleMode == HM_Rotate)
		applyRotateOpera(line);
	if (_handleMode == HM_Scale)
		applyScaleOpera(line);
	_dirtyAxis = true;
	this->fresh();
}
void PrimitiveHandler::applyMoveOpera(const BLine& line)
{
	BMatrix matrix = _transOpera->origin();
	BVector pos = matrix.position();
	BVector begin, end;
	switch (_handleAxis)
	{
	case HA_X:
		begin = _linePressed.closest(_axis_x);
		end = line.closest(_axis_x);
		break;
	case HA_Y:
		begin = _linePressed.closest(_axis_y);
		end = line.closest(_axis_y);
		break;
	case HA_Z:
		begin = _linePressed.closest(_axis_z);
		end = line.closest(_axis_z);
		break;
	case HA_XY:
	{
		BPlane plane(_quad_xy.normal(), pos);
		_linePressed.intersect(plane, begin);
		line.intersect(plane, end);
		break;
	}
	case HA_YZ:
	{
		BPlane plane(_quad_yz.normal(), pos);
		_linePressed.intersect(plane, begin);
		line.intersect(plane, end);
		break;
	}
	case HA_XZ:
	{
		BPlane plane(_quad_xz.normal(), pos);
		_linePressed.intersect(plane, begin);
		line.intersect(plane, end);
		break;
	}
	default:
		return;
	}
	BVector offset = end - begin;
	BVector newPos = pos + offset;
	matrix.setPosition(newPos);
	_transOpera->setMatrix(matrix);
	_transOpera->redo();
	_matrix = matrix;
	this->viewer()->fresh();
}
void PrimitiveHandler::applyRotateOpera(const BLine& line)
{
	BVector center = _matrix.position();
	BQuater rotate = _matrix.rotate();
	BVector begin, end;

	switch (_handleAxis)
	{
	case HA_XY:
	{
		BVector axis = rotate * BVector(0, 0, 1);
		BPlane plane_xy(axis, center);
		_linePressed.intersect(plane_xy, begin);
		line.intersect(plane_xy, end);

		begin -= center;
		end -= center;
		begin.normalize();
		end.normalize();

		BReal angle = begin.angle(end);
		BVector normal = begin.cross(end);
		if (normal.dot(axis) < 0.0f)
			angle = -angle;

		BMatrix matrix = _transOpera->origin();
		BVector euler = matrix.euler();
		euler.z() += angle;
		matrix.setEuler(euler);
		_transOpera->setMatrix(matrix);
		this->viewer()->fresh();
		break;
	}
	case  HA_YZ:
	{
		BVector axis = rotate * BVector(1, 0, 0);
		BPlane plane_yz(axis, center);
		_linePressed.intersect(plane_yz, begin);
		line.intersect(plane_yz, end);

		begin -= center;
		end -= center;
		begin.normalize();
		end.normalize();

		BReal angle = begin.angle(end);
		BVector normal = begin.cross(end);
		if (normal.dot(axis) < 0.0f)
			angle = -angle;

		BMatrix matrix = _transOpera->origin();
		BVector euler = matrix.euler();
		euler.x() += angle;
		matrix.setEuler(euler);
		_transOpera->setMatrix(matrix);
		this->viewer()->fresh();
		break;
	}
	case HA_XZ:
	{
		BVector axis = rotate * BVector(0, 1, 0);
		BPlane plane_xz(axis, center);
		_linePressed.intersect(plane_xz, begin);
		line.intersect(plane_xz, end);

		begin -= center;
		end -= center;
		begin.normalize();
		end.normalize();

		BReal angle = begin.angle(end);
		BVector normal = begin.cross(end);
		if (normal.dot(axis) < 0.0f)
			angle = -angle;

		BMatrix matrix = _transOpera->origin();
		BVector euler = matrix.euler();
		euler.y() += angle;
		matrix.setEuler(euler);
		_transOpera->setMatrix(matrix);
		this->viewer()->fresh();
		break;
	}
	default:
		break;
	}

}
void PrimitiveHandler::applyScaleOpera(const BLine& line)
{

}

void PrimitiveHandler::drawAxis(BRender& render)
{
	switch (_handleMode)
	{
	case HM_Move:
		drawMoveAxis(render);
		break;
	case HM_Rotate:
		drawRotateAxis(render);
		break;
	case HM_Scale:
		drawScaleAxis(render);
		break;
	default:
		break;
	}
}
void PrimitiveHandler::drawMoveAxis(BRender& render)
{
	render.setCullback(false);
	render.setDepthTest(false);

	BReal side = _axisSize * (BReal)0.1;
	if (_handleAxis & HA_X)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(255, 0, 0, 255);
	render.drawLine(_axis_x);
	_cone_x->setColor(render.color());
	render.drawShape(_cone_x);

	if (_handleAxis & HA_Y)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(0, 255, 0, 255);
	render.drawLine(_axis_y);
	_cone_y->setColor(render.color());
	render.drawShape(_cone_y);

	if (_handleAxis & HA_Z)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(0, 0, 255, 255);
	render.drawLine(_axis_z);
	_cone_z->setColor(render.color());
	render.drawShape(_cone_z);

	if (_handleAxis == HA_XY)
		render.setColor(255, 255, 0, 200);
	else
		render.setColor(255, 255, 0, 76);
	render.fillQuad(_quad_xy);

	if (_handleAxis == HA_YZ)
		render.setColor(255, 255, 0, 200);
	else
		render.setColor(0, 255, 255, 76);
	render.fillQuad(_quad_yz);

	if (_handleAxis == HA_XZ)
		render.setColor(255, 255, 0, 200);
	else
		render.setColor(255, 0, 255, 76);
	render.fillQuad(_quad_xz);
}
void PrimitiveHandler::drawRotateAxis(BRender& render)
{
	render.pushMatrix(_basicMatrix);

	render.setLighting(false);
	render.setDepthTest(true);

	if (_handleAxis == HA_XY)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(255, 0, 0, 255);
	render.drawLineLoop(_rotateCircleXY);

	if (_handleAxis == HA_YZ)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(0, 255, 0, 255);
	render.drawLineLoop(_rotateCircleYZ);

	if (_handleAxis == HA_XZ)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(0, 0, 255, 255);
	render.drawLineLoop(_rotateCircleXZ);

	render.setLighting(true);
	render.setDepthTest(true);

	if (_handleAxis)
		_rotateSphere->setColor(255, 255, 0, 200);
	else
		_rotateSphere->setColor(128, 128, 128, 200);
	render.drawShape(_rotateSphere);

	render.popMatrix();
}
void PrimitiveHandler::drawScaleAxis(BRender& render)
{

}

void PrimitiveHandler::slotTargetChanged(BObject* object, const BValue& value)
{
	_target = (Target*)value;
	freshTargetMatrix();
}

void PrimitiveHandler::attached(BViewer* viewer)
{
	BScene* scene = viewer->scene();
}
void PrimitiveHandler::detached(BViewer* viewer)
{

}

void PrimitiveHandler::paint(BPainter& painter)
{
	BRect crect = this->viewer()->centerRect();
	if (_leftPressed)
	{
		painter.setColor(234, 234, 234);
		painter.drawRect(_selectRect);
	}

	BSize imageSize(200, 136);
	BRect imageRect = crect.align(Align_RightBottom, imageSize);
	painter.setColor(128, 128, 128, 128);
	painter.fillRoundRect(imageRect, 16);
	painter.bind(this->camera());
	painter.fillRoundRect(imageRect, 16);
	painter.unbind();

}
void PrimitiveHandler::render(BRender& render)
{
	render.setLighting(false);
	render.setLineSmooth(true);
	if (_gridLinesVisible)
	{
		render.setLineWidth(1);
		render.setColor(_gridColor);
		render.drawLines(_horLines);
		render.drawLines(_verLines);
	}
	if (_visibleBaseAxes)
	{
		render.setLineWidth(2);
		render.setDepthOffset(-100);
		if (_visibleBaseAxes & HA_X)
		{
			render.setColor(_baseAxisXColor);
			render.drawLine(_baseAxisXLine);
		}
		if (_visibleBaseAxes & HA_Y)
		{
			render.setColor(_baseAxisYColor);
			render.drawLine(_baseAxisYLine);
		}
		if (_visibleBaseAxes & HA_Z)
		{
			render.setColor(_baseAxisZColor);
			render.drawLine(_baseAxisZLine);
		}
		render.setDepthOffset(0);
	}
	//render.setColor(255, 0, 0, 200);
	//render.fillQuad(_frustum.near_v0, _frustum.near_v1, _frustum.near_v2, _frustum.near_v3);
	//render.fillQuad(_frustum.far_v0, _frustum.far_v1, _frustum.far_v2, _frustum.far_v3);
	//render.setColor(255, 255, 0, 200);
	//render.fillQuad(_frustum.near_v0, _frustum.near_v1, _frustum.far_v1, _frustum.far_v0);
	//render.fillQuad(_frustum.near_v2, _frustum.near_v3, _frustum.far_v3, _frustum.far_v2);
	if (_target)
	{
		render.setLighting(false);
		render.setLineWidth(2);
		render.setLineSmooth(true);
		for (int i = 0; i < _target->pickHitCount(); i++)
		{
			BPickHit* hit = _target->pickHit(i);
			render.pushMatrix(hit->absoluteMatrix());
			if (BShape* shape = _target->shape())
			{
				BBox box = shape->box();
				drawNormals(shape, render);
				render.setColor(200, 200, 0);
				render.drawBox(box);
				if (const BGeometry* geometry = dynamic_cast<BGeometry*>(shape))
				{
					const BVectorArray* vertices = geometry->vertices();
					render.setColor(200, 0, 0);
					render.drawVertices(*vertices);
				}
			}
			if (BNode* node = _target->node())
			{
				BBox box = node->box();
				render.setColor(200, 200, 200);
				render.drawBox(box);
			}
			render.popMatrix();
			if (BGroup* group = _target->group())
			{
				BSpace space = group->space();
				render.setLineStipple(0xF0F0);
				render.setColor(0, 200, 200);
				render.drawSpace(space);
				render.setLineStipple(0);
			}
		}
		drawAxis(render);
	}
}

void PrimitiveHandler::updateEvent(const BEvent& event)
{
	if (_slideTimes > 0)
	{
		BVector position = this->camera()->position();
		BVector center = this->camera()->center();
		BVector up = this->camera()->up();

		position += (_slidePosition - position) / _slideTimes;
		center += (_slideCenter - center) / _slideTimes;
		up += (_slideUp - up) / _slideTimes;
		up.normalize();

		this->camera()->setPosition(position);
		this->camera()->setCenter(center);
		this->camera()->setUp(up);
		BReal dist = (position - center).length();
		if (this->camera()->far() < dist * 2)
			this->camera()->setFar(dist * 2);
		_slideTimes--;
	}
}
void PrimitiveHandler::styleEvent(const BEvent& event)
{
	if (const BStyle* style = event.value())
	{
		if (BImage* image = style->image("cursor-add"))
		{
			BCursor* cursor_add = new BCursor(image);
			this->setProperty("cursor-add", cursor_add);
		}
	}
}
void PrimitiveHandler::freshEvent(const BEvent& event)
{
	if (_dirtyGridLines)
	{
		BReal minx = -_gridSize.width() / 2;
		BReal maxx = _gridSize.width() / 2;
		BReal miny = -_gridSize.height() / 2;
		BReal maxy = _gridSize.height() / 2;
		BReal sx = _gridSize.width() / _gridSegment;
		BReal sy = _gridSize.height() / _gridSegment;
		_verLines.resize(_gridSegment + 1);
		for (int i = 0; i < _verLines.size(); i++)
		{
			BReal x = minx + sx * i;
			_verLines[i].set(x, miny, 0, x, maxy, 0);
		}
		_horLines.resize(_gridSegment + 1);
		for (int i = 0; i < _horLines.size(); i++)
		{
			BReal y = miny + sy * i;
			_horLines[i].set(minx, y, 0, maxx, y, 0);
		}
		_dirtyGridLines = false;

		if (BScene* scene = this->scene())
		{
			const BSpace& space = scene->space();
			_baseAxisXLine.set(minx, 0, 0, maxx, 0, 0);
			_baseAxisYLine.set(0, miny, 0, 0, maxy, 0);
			_baseAxisZLine.set(0, 0, 0, 0, 0, space.depth());
		}
	}
	if (_dirtyAxis && _target)
	{
		BMatrix matrix = _basicMatrix * _matrix;
		BVector center = matrix.position();
		BReal unit = this->viewer()->unit(center);
		BReal axisSize = unit * 120;
		if (_axisSize != axisSize)
		{
			_axisSize = axisSize;
			freshMoveAxis();
			freshRotateAxis();
			freshScaleAxis();
		}
		_dirtyAxis = false;
	}
}

void PrimitiveHandler::keyPressEvent(const BKeyEvent& keyEvent)
{
	if (keyEvent.key() == Key_Space)
	{
		BSpace space;
		if (_target)
			space = _target->space();
		if (space.empty())
			space = this->scene()->space();
		if (space.empty())
		{
			BReal minx = -_gridSize.width() / 2;
			BReal maxx = _gridSize.width() / 2;
			BReal miny = -_gridSize.height() / 2;
			BReal maxy = _gridSize.height() / 2;
			BReal hh = bMin(_gridSize.width(), _gridSize.height()) / 2;
			space.reset(minx, miny, -hh, maxx, maxy, hh);
		}
		if (space.valid())
		{
			BVector center = space.center();
			BVector direct(0, 1, 1);
			if (this->camera()->position() != center)
				direct = this->camera()->position() - center;
			direct.normalize();
			_slidePosition = center + direct * space.radius() * 3;
			_slideCenter = center;
			_slideUp.set(0, 0, 1);
			_slideTimes = 10;
		}
		keyEvent.accept();
		return;
	}
	if (keyEvent.key() == Key_LCtrl)
	{
		_ctrlDown = true;
		if (BCursor* cursor_add = this->property("cursor-add"))
			this->viewer()->setCursor(cursor_add);
		keyEvent.accept();
		return;
	}
	if (keyEvent.key() == Key_Delete)
	{
		emit("delete-target", _target);
		_target = 0;
		this->fresh();
		keyEvent.accept();
		return;
	}
}
void PrimitiveHandler::keyReleaseEvent(const BKeyEvent& keyEvent)
{
	if (keyEvent.key() == Key_LCtrl)
	{
		_ctrlDown = false;
		this->viewer()->setCursor(0);
		keyEvent.accept();
		return;
	}
}

void PrimitiveHandler::mousePressEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		const BPoint& pos = mouseEvent.pos();
		BLine line = this->viewer()->line(pos);
		if (_handleAxis)
		{
			_leftPressed = true;
			_linePressed = line;
			startTransform(_matrix);
			mouseEvent.accept();
			return;
		}
		_leftPressed = true;
		_pressedPoint = mouseEvent.pos();
		_selectRect.reset(_pressedPoint);
		this->fresh();
		mouseEvent.accept();
		return;
	}
	 BRoundHandler::mousePressEvent(mouseEvent);
}
void PrimitiveHandler::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (_leftPressed)
	{
		if (_matrix != _origin)
		{
			finishTransform(_matrix);
			_origin = _matrix;
			_dirtyAxis = true;
			this->fresh();
		}
		_leftPressed = false;
		mouseEvent.accept();
		return;
	}
	if (mouseEvent.button() == Button_Left)
	{
		_leftPressed = false;
		this->fresh();
		mouseEvent.accept();
		return;
	}
	BRoundHandler::mouseReleaseEvent(mouseEvent);
}
void PrimitiveHandler::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	BLine line = this->viewer()->line(pos);
	if (mouseEvent.button() == Button_None)
	{
		const BPoint& pos = mouseEvent.pos();
		BLine line = this->viewer()->line(pos);
		if (pickAxis(line))
		{
			_hoveredHit = 0;
			this->fresh();
			mouseEvent.accept();
			return;
		}
		else
		{
			BPickHit* hit = this->viewer()->pick(pos);
			bool equal = !_hoveredHit && !hit;
			if (!equal)
				equal = _hoveredHit && hit && _hoveredHit->node() == hit->node() && _hoveredHit->shape() == hit->shape();
			if (!equal)
			{
				_hoveredHit = hit;
				this->fresh();
				mouseEvent.accept();
				return;
			}
		}
	}
	if (mouseEvent.button() == Button_Left)
	{
		if (_handleMode && _handleAxis)
		{
			if (_handleMode == HM_Move)
				applyMoveOpera(line);
			if (_handleMode == HM_Rotate)
				applyRotateOpera(line);
			if (_handleMode == HM_Scale)
				applyScaleOpera(line);
			_dirtyAxis = true;
			transforming(_matrix);
			this->fresh();
			mouseEvent.accept();
			return;
		}
		_selectRect.reset(_pressedPoint);
		_selectRect.expand(pos);
		freshFrustum();
		frustumPick();
		bool ctrlPressed = BSystem::KeyState(Key_LCtrl);
		BScene* scene = this->viewer()->scene();
		Target* target = new Target(scene);
		if (ctrlPressed)
		{
			if (BPickHit* hit = target->matchPickHit(_hoveredHit))
			{
				target->removePickHit(hit);
			}
			else
			{
				target->addPickHit(_hoveredHit);
			}
		}
		else
		{
			target->clear();
			if (_hoveredHit)
			{
				target->addPickHit(_hoveredHit);
			}
		}
		if (!BSystem::KeyState(Key_LShift))
			target->clear();
		this->emit("target-changed", target);
		this->fresh();
		mouseEvent.accept();
		return;
	}
	BRoundHandler::mouseMoveEvent(mouseEvent);
}
void PrimitiveHandler::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (_ctrlDown)
		{
			BPoint pos = mouseEvent.pos();
			if (const BPickHit* hit = this->viewer()->pick(pos))
			{
				_focusPoint = hit->absolutePoint();
				BVector vec = _focusPoint - this->camera()->position();
				BVector direct = this->camera()->center() - this->camera()->position();
				direct.normalize();
				BReal distance = direct.dot(vec);
				BVector center = this->camera()->position() + direct * distance;
				this->camera()->setCenter(center);
			}
		}
		if (_hoveredHit)
		{
			if (_target == 0)
				_target = new Target(this->scene());
			else
				_target->clear();
			_target->addPickHit(_hoveredHit);
			freshTargetMatrix();
		}
		else
		{
			_target = new Target(this->scene());
		}
		emit("target-changed", _target);
		this->fresh();
		mouseEvent.accept();
		return;
	}
	BRoundHandler::mouseClickEvent(mouseEvent);
}

